#ifndef __CORDET_H__
#define __CORDET_H__

class Cordet{

public:
	int detectCorners(
    float *image_p,              
           /* The array containing the values of brightness. 
           Please note that the values are represented as floats.    
           Important: The algorithm does not detect the corners at the     
           border of the image. The width of this border is halfMaskSize+1.
           This usually does not matter. If it could be a problem, place   
           your image into a bigger one whose sizes are increased by       
           2*(halfMaskSize+1) in both directions. Have in mind this fact   
           also if you are preparing the reference solution (see above).   
           In noisy images, according to our experience, it is often useful
           to convolve the image with the Gaussian prior to the corner     
           detection. The value of sigma=0.5 proved to be suitable for     
           most images. You should perform this convolution for yourself   
           before calling the function detectCorners.                      */

    int    xImageSize_p,         /* width of image                            */
    int    yImageSize_p,         /* height of image                           */

    int    halfPsgMaskSize_p,    
            /* The half of the mask size. The overall    
            mask size, i.e., the size of the neighbourhood that is used to  
            decide whether or not a candidate is a corner, then is          
            (2*halfMaskSize + 1). Generally, the bigger masks give          
            better results but the computation may be longer. The usual     
            values of halfMaskSize vary from 4 to 7, which gives the overall
            size of the mask between 9x9 and 15x15 pixels.                  */

    float  angleThresh_p,        
            /* The threshold for the "angle of break" of 
            the boundary at the corner point. Only a point at which the     
            boundary is broken more than is required by this threshold may  
            be accepted as a corner. Usual value is approximately 0.5, which
            is an angle size in radians. As an explanation, I point out that
            due to noises, the values of small angles that are computed by  
            the algorithm are always slightly higher than the angles you    
            see in the images. The value of this threshold is more or less  
            stable for all images. Therefore, you need not experiment too   
            much unless you want to detect corners with a specific angle.   
            Perhaps, you should choose a higher value of this threshold if  
            you use small masks since in small masks, the precision of      
            measuring the angles is generally lower than in greater masks.  
            In some cases (in nice,not too noisy images), on the other hand,
            you may be able to detect even the corners with the break angle 
            less than 0.5. You can try the values down to approx. 0.3.)     */

    float  noiseGradSizeThresh_p,
           /* The threshold for the size of the gradient
           of brightness. All the values of the gradient size less than    
           this threshold are considered to be a noise and the corresponding 
           points are therefore excluded from processing. Higher      
           values of this threshold contribute to the reduction of influence 
           of noise. At the same time, however, the less obvious    
           corners may be missed. Remember that even in the synthetic      
           images you have a noise that is caused by dividing the image    
           into pixels. Typically, the value of this parameter varies      
           between 0.04 and 0.08 of the image range (the difference between
           the maximal and minimal value of brightness in the image).      
           Fine tuning of this threshold for your images is desirable. You 
           can start e.g. from the value (0.06*image range). After trying  
           how it works, lower this value if you want that the less con-   
           trast corners be detected. You should increase the value of this
           threshold, if the corners caused by noise are detected. If you  
           decided to minimise the error, set the value of this threshold  
           to the value giving the lowest possible error. The optimal value
           of this threshold should not depend too much on the the values  
           of the remaining parameters. Let it be also pointed out that    
           the higher values also lead to faster computation since the     
           algorithm examines a lower number of candidates.                */

    float  apparenceThresh_p,    
           /* The threshold for the "apparence"         
           (obviousness) of corner. The apparence combines the contrast,   
           size and the shape of the possible corner area. Only the points 
           whose apparence is greater than this threshold can be accepted  
           as corners. The value of this threshold must again be properly  
           adjusted for your images. The typical value of this threshold   
           varies usually between 0.0 and 5.0. You can start, for example, 
           from the value 2.0. If the algorithm detects too many corners,  
           increase the value of this threshold and vice versa. We remark  
           that the value of this theshold may be even negative (you can   
           try a negative value if the detectors misses the T corners). We 
           recommend to experiment with the value of this threshold after  
           preliminarily setting the previous threshold.                   */

    float  meanGradSizeThresh_p, 
           /* The threshold for the mean value of the   
            gradient magnitude over the area of corner. This threshold is   
            used only for the final testing of the acceptability of the     
            corners. If you do not require this test, set this value simply 
            to 0.0 (in this case, the decision is made on the basis of      
            apparenceThresh_p) If, on the other hand, you want that the test
            be carried out, you should set this parameter to a value that is
            greater than the value of noiseGradSizeThresh_p ( simply: what  
            is less than noiseGradSizeThresh_p is a noise, the mean value   
            of the required gradient magnitude over the corner area should  
            therefore be greater).                                          */

    float  inertiaRadiusThresh_p,
           /* The threshold for the radius of inertia of
           the corner area. The radius checks the size of the corner area. 
           Again, this threshold is used only for the final testing of the 
           acceptability of the corners. If you do not require this test,  
           set this value simply to 0.0. If you want that the test be      
           carried out, set this threshold to a value between, say, 1.0 and
           3.0 (greater values mean that you want only "bigger" corners).  */

    float  sigmaD_p,             
           /* "Sigma" for the normal distribution       
           of the probability density pd(). From the theoretical point     
           of view, it follows that the value should be less than 1.0.     
           Values between 0.7 and 1.0 were confirmed as optimal also    
           experimentally. The value of 0.95 proved to be suitable for most
           images. You need not experiment with this value too much. Only 
           if you want to obtain the absolutely best possible detection    
           for your images you could make some trials. You should carry out
           them after preliminarily setting the values of the previously   
           mentioned parameters. In the case of change, you should check   
           the values of the remaining parameters again.                   */

    float  sigmaR_p,             
           /* "Sigma" for the Gaussian expressing the   
            the function wr(), i.e., the weights depending on the distances 
            from the candidate that is just being processed. For the above  
            mentioned sizes of the mask, use the values between 2.5 and 3.5,
            typically 3.0. Usually, the value is not critical. Again, you   
            can check the value of this parameter, e.g., at the end, after  
            you have found the values for all the remaining parameters.     */

    int    halfExtMaskSize_p,    
           /* This parameter says what is the size of   
            the area in which it is checked whether the corner response     
            function corr() has its maximum at the point just being tested. 
            Typical value of this parameter is 1, which means that the      
            maximum is checked in the area of 3x3 pixels with the point     
            being tested in its center. You should start with this value.   
            Only if you have problems with multiple detections of the same  
            corners, you could try to use a higher value of this parameter, 
            typically the value of 2 or 3. The value of this parameter must 
            always be less than or equal to the value of the parameter      
            halfPsgMaskSize_p.                                              */

    int    options_p,            
           /* Here you can specify the actions that are 
           carried out optionally. You can use the following values:       
           
           BIT 0: Sort the corners in the output cornerList according to   
           their apparence.                                                
           
           BIT 2: If the bit is set, the corner apparence is modified by   
           determining the gradient-size signal-to-noise ratio in the      
           neighbourhood of Q. If you do not use this option, the value    
           of noiseGradSizeThresh_p is used as an estimation of the level  
           of noise. If you use this option, the algorithm will try to     
           estimate the level of noise more exactly by analysing the       
           neighbourhood of Q. You can try to use this option if you want  
           the apparence to correspond more exactly to the obviousness of  
           corners as is perceived by humans. Please, take this option as  
           experimantal (at the moment).                                   */

    int    *cornerList,          /* Here you pass the array into which the    
            output is written. The x,y coordinates are written to this array
            for each corner. The function returns the number of corners that
            were found.                                                     */

    int    cornerListLen );      /* Here you say how long array for the       
            corners you have. The length should be an even number (one item 
            for each coordinate). In case that more corners than            
            cornerListLen/2 are found, the function returns -2. In this     
            case, the cornerList contains the first cornerListLen/2 corners.*/

/* The function returns either the number of corners that were found or -1    
 * if there was not enough memory to solve the task or -2 if the array        
 * "cornerList" was not big enough for all the corners that were found.       */
/*============================================================================*/

	#define SORT_CORNERS    1
	#define CHECK_APPAR_SNR 2
private:
	/*----------------------------------------------------------------------------*/
	/* Some private variables follow that are mostly used to save the parameters. */
	/* If you want just only to try or use the detector do not look at them.      */
	/* If you want to study the program, I recommend reading the theory first     */
	/* since the identifiers usually correspond with the notation introduced      */
	/* there.                                                                     */
	/*                                                                            */
	float *image;                 /* pointer to the input image                   */
	int    xImageSize;            /* width of the input image                     */
	int    yImageSize;            /* height of the input image                    */
	int    numImagePixs;          /* number of pixels in the image                */
	int    halfPsgMaskSize;       /* the overall mask size is 2*halfMaskSize + 1  */
	int    PsgMaskSize;           /* the overall mask size, mask = neighbourhood  */
	int    PsgMaskCenter;         /* index of centerpoint in mask                 */
	int    numPsgMaskPixs;        /* number of pixels in Psg mask                 */
	float  noiseGradSizeThresh;   /* threshold for the gradient size              */
	float  meanGradSizeThresh;    /* threshold for the mean gradient size over    */
	float  inertiaRadiusThresh;   /* threshold for the corner area size           */
	float  halfGradSizeThresh;    /* one half of the value above                  */
	float  tenthGradSizeThresh;   /* one tenth of gradSizeThresh                  */
	float  angleThresh;           /* threshold for the break angle at the corner  */
	float  halfAngleThresh;       /* simply the half of the above value           */
	float  apparenceThresh;       /* threshold for the apparence of the corner    */
	float  angleVal1;             /* dfi(X) less than this value is not reduced   */
	float  angleVal2;             /* dfi(X) greater than this value is ignored    */
	float  sigmaD;                /* sigma for the probability density pd()       */
	float  sigmaR;                /* sigma for the weight function wr()           */
	float  invAngleRampWidth;     /* a precomputed value to save time             */
	float *gSizes;                /* sizes of the gradient of brightness, g(X)    */
	float *dets;                  /* values of Beaudet's Det prop. to curvature   */
	float *gDirs;                 /* directions of the gradient, fi(X)            */
	short *gDsins;                /* sins of fi(X) to speed up the computation    */
	short *gDcoss;                /* coss of fi(X) for the same reason            */
	float *corrDirs;              /* directions of corners                        */
	float *corrs;                 /* corner measures, corr(Q)                     */
	float *appars;                /* corner apparences, appar(Q)                  */
	float *SNRs;                  /* Signal-To-Noise ratio for corner candidates  */
	int   *neighbMap;             /* maps neighbourhood of Q into all image files */
	float *Psgs;                  /* values of Psg(X) for Q just being processed  */
	float *Wrs;                   /* the values of the weight Wr(x,y)             */
	float *PsgWrs;                /* the values of PsgWr(X)                       */
	int   *xs,*ys;                /* x and y coordinates of the points in the mask*/
	float *dirXs;                 /* directions towards the points in the mask    */
	float *diffDirXs;             /* differences between fi(Q) and fi(X)          */
	int   *flagsProcess;          /* flags "the point will be processed"          */
	int   *influenceMap;          /* map of points influenced by Psg(X)           */
	int   *influences;            /* number and indices of influenced points      */
	float *intCoefs;              /* coefficients for interpolating Psg(X)        */
	int   *importantPixs;         /* list of pixels relevant for measuring at Q   */
	int    numImportantPixs;      /* number of the pixels in the above list       */
	int   *tobeProcessed;         /* influenced points waiting for processing     */
	float *pdTable;               /* the values of probability density pd()       */
	int    pdTableSize;           /* the size of the table stated above           */
	int    pdTableScale;          /* values are tabulated with step 1/pdTableScale*/
	float  pdTableScalef;         /* the same but represented as a float          */
	float  pdTableScale2f;        /* the value stated above multiplied by 2.0     */
	short *isCandidate;           /* contains 1 at points where corr() has maxima */
	int    halfExtMaskSize;       /* in the neighbourhood of this size, the maxima*/
	                              /* of coors(Q) will be checked                  */
	int   *corners;               /* pointer to array containing the corners      */
	int    options;               /* options required for "detectCorners"         */

	/* Functions */	
	void createNeighbMap(void);
	void createXsYsTables(void);
	void createWrTable(void);
	void createDirXTable(void);
	void computeGrads(void);
	void computeDets(void);
	float estimateNoiseSigma(int imgPosQ);
	void createPdTable(void);
	void inline send3(int x,int y,int s1,int s2,int s3,int &q, float c);
	void inline send2(int x,int y,int s1,int s2,int &q, float c1, float c2);
	void createOrgTables(int halfMaskSize);
	inline void diffAngles(float a1,float a2,float &d);
	int createPsgMap(int imgPosQ);
	
	void measureCornerCandidate(int imgPosQ, float *variance,
            float *apparence, float *corrDir,
            float *meanGr, float *inertiaRadius);
	
	void computeMeasuresAndApparences(void);
	short isCorrMax(int imgPosQ);
	void markCandidates(void);
	void modifyApparency(void);
	int checkCornerInGreaterNeighbourhood(int imgPosQ);
	int decideCorners(int *cornerList, const int cornerListLen);
	void sortCorners( int l, int r );
};


#endif

